package com.mxx.common.netty.http;

import com.mxx.common.netty.exception.IllegalParameterException;
import com.mxx.common.netty.http.resolvers.NettyResolvers;
import com.mxx.common.netty.http.validate.ParameterValidator;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;


/**
 * @Auther: Mr. Zeng
 * @Date: 2020/8/3 19:58
 * @Description: 暂无描述
 */

public final class NettyMethod {

    private Class<?> metaClass;
    private NettyPath nettyPath;
    private Method method;
    private Object metaHandler;
    private List<ParameterValidator> validators = Collections.EMPTY_LIST;
    private NettyMethodParameter[] methodParameters;
    private boolean init;

    public NettyMethod(NettyPath nettyPath, Object metaHandler, Method method) {
        this.nettyPath = nettyPath;
        this.metaHandler = metaHandler;
        this.metaClass = metaHandler.getClass();
        this.method = method;
        this.init = false;
    }

    public Class<?> getMetaClass() {
        return metaClass;
    }

    public Object getMetaHandler() {
        return metaHandler;
    }

    public NettyPath getNettyPath() {
        return nettyPath;
    }

    public <T extends Annotation> T getAnnotation(Class<T> classes) {
        return method.getAnnotation(classes);
    }

    public Method getMethod() {
        return method;
    }

    public void loadMValidator(Collection<ParameterValidator> validators) {
        this.validators = new ArrayList<>();
        for (ParameterValidator validator : validators) {
            if (validator.match(this)) {
                this.validators.add(validator);
            }
        }
    }


    public void initMethodParameter(Collection<NettyResolvers> resolvers) {
        if (!this.init) {
            Parameter[] parameterArray = this.method.getParameters();
            methodParameters = new NettyMethodParameter[parameterArray.length];
            for (int i = 0; i < parameterArray.length; i++) {
                NettyMethodParameter parameter = new NettyMethodParameter(this, parameterArray[i], i);
                methodParameters[i] = parameter;
                for (NettyResolvers resolver : resolvers) {
                    if (resolver.match(this, parameter)) {
                        parameter.setResolvers(resolver);
                        break;
                    }
                }
            }
            this.init = true;
        }
    }

    public Object invoke(NettyHttpRequest request) throws Exception {
        Object[] param = this.getRequestParamValue(request);
        for (ParameterValidator validator : this.validators) {
            validator.validate(this, param);
        }
        return this.method.invoke(this.metaHandler, param);
    }

    public NettyMethodParameter[] getMethodParameters() {
        return methodParameters;
    }

    private Object[] getRequestParamValue(NettyHttpRequest request) throws IllegalParameterException {
        Object[] param = new Object[this.methodParameters.length];
        NettyMethodParameter parameter = null;
        try {
            for (int i = 0; i < this.methodParameters.length; i++) {
                parameter = this.methodParameters[i];
                param[i] = parameter.getVal(request);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new IllegalParameterException(String.format("url:%s,illegalParameter %s", request.getUrl(), parameter.getName()));
        }
        return param;
    }


}
